package cn.xyt.server;

import java.io.IOException;
import java.util.Properties;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import cn.tom.db.jdbc.simple.DBUtil;
import cn.tom.kit.io.PropertiesUtil;
import cn.tom.kit.io.Resource;
import cn.tom.mvc.config.Constants;
import cn.xyt.dto.SystemProperty;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.Epoll;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;

@Service
public class ServerBootStart {
	private static final Logger LOG = LoggerFactory.getLogger(ServerBootStart.class);
	@Autowired
	private SystemProperty property;
	@Autowired
	MessageInDecoder messageInDecoder;
	
	private int workthreads = Runtime.getRuntime().availableProcessors();
	private int bossthreads = workthreads/2;
	
	void initServer()throws InterruptedException {
		ServerBootstrap bootstrap = new ServerBootstrap();// 启动辅助类
		EventLoopGroup boss = null;
		EventLoopGroup worker = null;
		if (Epoll.isAvailable()) {
			boss = new EpollEventLoopGroup(bossthreads);
			worker = new EpollEventLoopGroup(workthreads);
			bootstrap.channel(EpollServerSocketChannel.class);// linux
		} else {
			boss = new NioEventLoopGroup(bossthreads);
			worker = new NioEventLoopGroup(workthreads);
			bootstrap.channel(NioServerSocketChannel.class);//其他
		}
		try{
			bootstrap.group(boss, worker);
			bootstrap.option(ChannelOption.SO_BACKLOG, 128);
			bootstrap.option(ChannelOption.TCP_NODELAY, true);
			bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
			bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
				@Override
				protected void initChannel(SocketChannel socketChannel) throws Exception {
					int deviceHeartTime = ServerBootStart.this.property.getDeviceHeart().intValue();
					ChannelPipeline p = socketChannel.pipeline();
					p.addLast("logging", new LoggingHandler(LogLevel.INFO)); // 添加byte 数据日志, 用于调试
					//读, 写, 总超时
					p.addLast("idleStateHandler", new IdleStateHandler(0, 0, deviceHeartTime)); 
					p.addLast("heartHandler", new HeartHandler());
					
					p.addLast("BaseInDecode", new BaseInDecoder()); // in 顺序
					p.addLast("messageInDecoder", messageInDecoder);
					p.addLast("BaseOutEncoder", new BaseOutEncoder()); 
					/*p.addLast("encoder1", new Encoder()); // out 逆序*/
					
					/* 执行顺序BaseInDecode ->MessageDecoder  ->messageEncoder ->[out]encoder1 -->  BaseOutEncoder ->*/
					
				}
			});
			ChannelFuture f = bootstrap.bind(this.property.getMessageServerPort().intValue()).sync();
			if (f.isSuccess()) {
				LOG.info("*****************MessageServer start success******************************");
			} else {
				LOG.info("*****************MessageServer start faild******************************");
			}
			 f.channel().closeFuture().sync();
			 System.out.println("----");
		}finally{
            boss.shutdownGracefully();
            worker.shutdownGracefully();
		}
	}
	
	@PostConstruct
	void init() throws InterruptedException, IOException {
		initDataSource();
		
		Thread th = new Thread(new Runnable() {
			
			@Override
			public void run() {
				try {
					initServer();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
		th.setDaemon(false);
		th.start();
	}
	
	
	public void initDataSource() throws IOException{
//		new DefaultLogConfigure().config();
		Resource resource = new Resource(ServerBootStart.this.property.getDBconfig());
		Properties props = PropertiesUtil.loadProperties(resource);
		if("SQL".equals(Constants.getDBType())){
			DBUtil.init(props);
			return;
		}
	}

	@PreDestroy
	public void destroy() {
	}
}
